package jp.cane.android.luciferblue;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

import android.app.Notification;
import android.app.PendingIntent;
import android.app.Service;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.util.Log;

public class MainService extends Service implements Runnable {
	private static final String TAG = "MainService";

	public static BluetoothDevice device = null;
	private static BluetoothSocket socket = null;

	// RemoteCallbackListというClassを用意しCallback Interfaceを保持する
	private RemoteCallbackList<MainServiceObserver> mObservers = new RemoteCallbackList<MainServiceObserver>();

	private Thread thread = null;

	// ServiceでAIDL fileに定義したinterfaceの実装
	// ただし、生成されたjava fileのStub classを実装する
	private final MyBindService.Stub mMyBindService = new MyBindService.Stub() {
		public String getString() throws RemoteException {
			Log.d(TAG, "getString called by "
					+ Thread.currentThread().getName());
			return "This string is provided by Service";
		}

		// Observer登録method内でRemoteCallbackList#register()
		// methodで引数に渡されたCallback interfaceを登録する
		public void setObserver(MainServiceObserver observer)
				throws RemoteException {
			Log.d(TAG, "setObserver called by "
					+ Thread.currentThread().getName());
			mObservers.register(observer);
		}

		// Observer解除method内でRemoteCallbackList#register()
		// methodで引数に渡されたCallback interfaceを削除する
		public void removeObserver(MainServiceObserver observer)
				throws RemoteException {
			Log.d(TAG, "removeObserver called by "
					+ Thread.currentThread().getName());
			mObservers.unregister(observer);
		}
	};

	// 生成したStub classをService#onBind()でreturnする
	@Override
	public IBinder onBind(Intent arg0) {
		// Toast.makeText(mContext,
		// "onBind called by " + Thread.currentThread().getName(),
		// Toast.LENGTH_LONG).show();
		return mMyBindService;
	}

	@Override
	public boolean onUnbind(Intent intent) {
		// Toast.makeText(mContext,
		// "onUnbind called by " + Thread.currentThread().getName(),
		// Toast.LENGTH_LONG).show();
		return true;
	}

	@Override
	public void onCreate() {
		// Toast.makeText(mContext,
		// "onCreate called by " + Thread.currentThread().getName(),
		// Toast.LENGTH_LONG).show();
		super.onCreate();

		Notification notification = new Notification(R.drawable.icon,
				getText(R.string.app_name), System.currentTimeMillis());
		Intent notificationIntent = new Intent(this, MainActivity.class);
		PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
				notificationIntent, 0);
		notification.setLatestEventInfo(this, getText(R.string.app_name),
				getText(R.string.app_name), pendingIntent);
		startForeground(1, notification);

		this.thread = new Thread(this);
		this.thread.start();
	}

	@Override
	public void onDestroy() {
		// Toast.makeText(mContext,
		// "onDestroy called by " + Thread.currentThread().getName(),
		// Toast.LENGTH_LONG).show();
		super.onDestroy();
	}

	@Override
	public void onRebind(Intent intent) {
		// Toast.makeText(mContext,
		// "onRebind called by " + Thread.currentThread().getName(),
		// Toast.LENGTH_LONG).show();
		super.onRebind(intent);
	}

	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		// Toast.makeText(mContext,
		// "onStartCommand called by " + Thread.currentThread().getName(),
		// Toast.LENGTH_LONG).show();
		return START_STICKY;
	}

	private void append(String message) {
		// Callback intefaceのCallback methodを呼び出す為に
		// RemoteCallbackList#beginBroadcat()でCallbackの準備
		int observerNum = mObservers.beginBroadcast();
		for (int i = 0; i < observerNum; i++) {
			try {
				// RemoteCallbackList#getBroadcastItem()でCallback
				// interfaceを取り出し
				// Callback methodを呼び出す
				mObservers.getBroadcastItem(i).appendLog(message);
			} catch (RemoteException e) {
			}
		}
		// RemoteCallbackList#finishBroadcast()でbroadcast
		// stateをclear
		mObservers.finishBroadcast();
	}

	private void change(String message) {
		// Callback intefaceのCallback methodを呼び出す為に
		// RemoteCallbackList#beginBroadcat()でCallbackの準備
		int observerNum = mObservers.beginBroadcast();
		for (int i = 0; i < observerNum; i++) {
			try {
				// RemoteCallbackList#getBroadcastItem()でCallback
				// interfaceを取り出し
				// Callback methodを呼び出す
				mObservers.getBroadcastItem(i).onDataReady(message);
			} catch (RemoteException e) {
			}
		}
		// RemoteCallbackList#finishBroadcast()でbroadcast
		// stateをclear
		mObservers.finishBroadcast();
	}

	public void run() {
		while (true) {
			try {
				if (true) {
					append("Connected");
					for (int i = 0; i < 300; i++) {
						String line = "" + i;
						change(line);
						append("<font color='red'>" + line + "</font>");
						try {
							Thread.sleep(1000);
						} catch (InterruptedException e) {
						}
					}
				} else {
					if (device != null && socket == null) {
						socket = device
								.createRfcommSocketToServiceRecord(BluetoothProtocols.SERIAL_PORT_PROTOCOL_UUID);
						socket.connect();
					} else {
						try {
							Thread.sleep(10 * 1000);
						} catch (InterruptedException e) {
						}
						append("Scoket abuse");
						continue;
					}
					append("Connected");

					BufferedReader reader = new BufferedReader(
							new InputStreamReader(new BufferedInputStream(
									socket.getInputStream())));
					while (true) {
						String line = reader.readLine();
						if (line == null) {
							break;
						}
						line = line.replaceAll("\0", "");
						change(line);
						append("<font color='red'>" + line + "</font>");
					}
					// } catch (InterruptedException e) {
					// closeSocket();
					// append("Closed.");
				}
			} catch (IOException e) {
				e.printStackTrace();
			} finally {
				closeSocket();
				append("Closed.");
			}
		}
	}

	public static void send(String str) {
		if (socket != null) {
			try {
				BufferedOutputStream os = new BufferedOutputStream(
						socket.getOutputStream());
				os.write((str).getBytes());
				os.flush();
			} catch (IOException e) {
			}
		}
	}

	private void closeSocket() {
		if (socket != null) {
			try {
				socket.close();
			} catch (Exception e) {
			}
		}
		socket = null;
	}
}
